﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace ETModel
{

    [ObjectSystem]
    public class SoundComponentAwakeSystem : AwakeSystem<SoundComponent>
    {
        public override void Awake(SoundComponent self)
        {
            self.Awake();
        }
    }

    public class SoundComponent : Component 
    {

        public static SoundComponent Instance;
        const int MAX_SOUNDS = 8;
        private AudioSource music;
        private AudioSource[] sounds = new AudioSource[MAX_SOUNDS];


        private int musicMuted;
        private int soundMuted;

        private float musicVolume;
        private float soundVolume;

        private int nowSoundId = 0;

        struct ExAudioClip
        {
            public AudioClip clip;
            public int index;
        }
        private Dictionary<string, ExAudioClip> cacheClipDic = new Dictionary<string, ExAudioClip>();
        public void Awake()
        {
            Instance = this;

            this.musicMuted = PlayerPrefs.GetInt("music_muted", 0);
            this.soundMuted = PlayerPrefs.GetInt("sound_muted", 0);
            this.musicVolume = PlayerPrefs.GetFloat("music_volume", 1.0f);
            this.soundVolume = PlayerPrefs.GetFloat("sound_volume", 1.0f);


            this.music = this.GameObject.AddComponent<AudioSource>();
            this.music.mute = (this.musicMuted == 1);
            this.music.volume = (this.musicVolume);

            for (int i = 0; i < MAX_SOUNDS; i++)
            {
                this.sounds[i] = this.GameObject.AddComponent<AudioSource>();
                this.sounds[i].mute = (this.soundMuted == 1);
                this.sounds[i].volume = (this.soundVolume);
            }
            Game.Scene.GetComponent<ResourcesComponent>().LoadBundle("sounds.unity3d");
        }

        public void PlayMusic(string url, bool loop = true)
        {
            AudioClip clip = null;
            if (cacheClipDic.ContainsKey(url))
            {
                clip = cacheClipDic[url].clip;
            }
            else
            {
                clip = (AudioClip)Game.Scene.GetComponent<ResourcesComponent>().GetAsset("sounds.unity3d", url);
            }
            if (clip == null)
            {
                Log.Error("LoadAssetAsync clip err : " + url);
                return;
            }
            this.music.clip = clip;
            this.music.loop = loop;
            this.music.Play();
            ExAudioClip exClip;
            exClip.clip = clip;
            exClip.index = -1;
            cacheClipDic[url] = exClip;
        }

        public void PlaySound(string url, bool loop = false)
        {
            AudioClip clip = null;
            if (cacheClipDic.ContainsKey(url))
            {
                clip = cacheClipDic[url].clip;
            }
            else
            {
                clip = (AudioClip)Game.Scene.GetComponent<ResourcesComponent>().GetAsset("sounds.unity3d", url);
            }
            if (clip == null)
            {
                Log.Error("LoadAssetAsync clip err : " + url);
                return;
            }
            this.sounds[this.nowSoundId].clip = clip;
            this.sounds[this.nowSoundId].loop = loop;
            this.sounds[this.nowSoundId].Play();

            this.nowSoundId++;
            this.nowSoundId = (this.nowSoundId >= this.sounds.Length) ? 0 : this.nowSoundId;
            ExAudioClip exClip;
            exClip.clip = clip;
            exClip.index = nowSoundId;
            cacheClipDic[url] = exClip;
        }

        public void PlayOneShot(string url, bool loop = false)
        {
            AudioClip clip = null;
            if (cacheClipDic.ContainsKey(url))
            {
                clip = cacheClipDic[url].clip;
            }
            else
            {
                clip = (AudioClip)Game.Scene.GetComponent<ResourcesComponent>().GetAsset("sounds.unity3d", url);
            }
            if (clip == null)
            {
                Log.Error("LoadAssetAsync clip err : " + url);
                return;
            }
            this.sounds[this.nowSoundId].clip = clip;
            this.sounds[this.nowSoundId].loop = loop;
            this.sounds[this.nowSoundId].PlayOneShot(clip);

            this.nowSoundId++;
            this.nowSoundId = (this.nowSoundId >= this.sounds.Length) ? 0 : this.nowSoundId;
            ExAudioClip exClip;
            exClip.clip = clip;
            exClip.index = nowSoundId;
            cacheClipDic[url] = exClip;
        }

        
        public void StopSound(string url)
        {
            ExAudioClip exClip;
            if (!cacheClipDic.TryGetValue(url,out exClip))
            {
                return;
            }
            if (this.sounds[exClip.index].clip == exClip.clip)
            {
                this.sounds[exClip.index].Stop();
                this.sounds[exClip.index].clip = null;
            }           
        }

        public void StopMusic()
        {
            this.music.Stop();
            this.music.clip = null;
        }

        public void StopAllSounds()
        {
            for (int i = 0; i < this.sounds.Length; i++)
            {
                this.sounds[i].Stop();
                this.sounds[i].clip = null;
            }
        }

        public void SetMusicMute(bool mute)
        {
            if (mute == (this.musicMuted == 1))
            {
                return;
            }

            this.musicMuted = mute ? 1 : 0;
            this.music.mute = mute;

            PlayerPrefs.SetInt("music_muted", this.musicMuted);
        }

        public void SetSoundMute(bool mute)
        {
            if (mute == (this.soundMuted == 1))
            {
                return;
            }

            this.soundMuted = (mute) ? 1 : 0;
            for (int i = 0; i < MAX_SOUNDS; i++)
            {
                this.sounds[i].mute = mute;
            }

            PlayerPrefs.SetInt("sound_muted", this.soundMuted);
        }

        public void SetMusicVolume(float value)
        {
            if (value < 0.0f || value > 1.0f)
            {
                return;
            }

            this.musicVolume = value;
            this.music.volume = this.musicVolume;
            PlayerPrefs.SetFloat("music_volume", this.musicVolume);
        }

        public void SetSoundVolume(float value)
        {
            if (value < 0.0f || value > 1.0f)
            {
                return;
            }

            this.soundVolume = value;
            for (int i = 0; i < MAX_SOUNDS; i++)
            {
                this.sounds[i].volume = value;
            }

            PlayerPrefs.SetFloat("sound_volume", this.soundVolume);
        }

        public bool MusicMuted
        {
            get
            {
                return (this.musicMuted == 1);
            }
        }

        public bool SoundMuted
        {
            get
            {
                return (this.soundMuted == 1);
            }
        }

        public float MusicVolume
        {
            get
            {
                return this.musicVolume;
            }
        }

        public float SoundVolume
        {
            get
            {
                return this.soundVolume;
            }
        }
    }
}